package com.yusong.evenserialportdemo;


import android.os.HandlerThread;
import android.os.SystemClock;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android_serialport_api.SerialPort;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;


/**
 * Created by Administrator on 2017/3/28 0028.
 */
public abstract class SerialPortManager {

    private static final String TAG = "SerialPortManager";

    private SerialReadThread mReadThread;
    private OutputStream mOutputStream;
    private HandlerThread mWriteThread;
    private Scheduler mSendScheduler;

    //默认 N-8-1
    private char parity = 'N';//char校验类型 取值N ,E, O,,S
    private int dataBits = 8;//dataBits 类型 int数据位 取值 位7或8
    private int stopBits = 1;//stopBits 类型 int 停止位 取值1 或者 2




    private BufferedInputStream mInputStream;
    private ReadThread thread;
//    private ReadDataListener readDataListener;

//    private static class InstanceHolder {
//        public static SerialPortManager sManager = new SerialPortManager();
//    }
//
//    public static SerialPortManager instance() {
//        return InstanceHolder.sManager;
//    }

    private SerialPort mSerialPort;

    protected SerialPortManager() {

    }

    /**
     *
     * @param device
     * @param dataBits     dataBits 类型 int数据位 取值 位7或8
     * @param stopBits     stopBits 类型 int 停止位 取值1 或者 2
     * @param parity       char校验类型 取值N ,E, O,,S
     * @return
     */
    public SerialPort open(Device device,int dataBits, int stopBits, char parity) {
        return open(device.getPath(), device.getBaudrate(),dataBits,stopBits,parity);
    }

    /**
     * 打开串口
     *
     * SSP入钞协议
     * 波特率 9600 bps
     * 数据位 8 Bits
     * 起始位 1Bis
     * 停止位 2Bits
     * 校验位 无
     *
     * @param devicePath
     * @param baudrate
     * @return
     */
    public SerialPort open(String devicePath, String baudrate, int dataBits, int stopBits, char parity) {
        if (mSerialPort != null) {
            close();
        }

        try {
            File device = new File(devicePath);
            int baurate = Integer.parseInt(baudrate);
//            mSerialPort = new SerialPort(device, baurate,0);
            mSerialPort = new SerialPort(device, baurate, dataBits,stopBits,parity);

//            mReadThread = new SerialReadThread(mSerialPort.getInputStream());
//            mReadThread.start();

            thread = new ReadThread(mSerialPort.getInputStream());
            thread.start();

            mOutputStream = mSerialPort.getOutputStream();

            mWriteThread = new HandlerThread("write-thread");
            mWriteThread.start();
            mSendScheduler = AndroidSchedulers.from(mWriteThread.getLooper());

            return mSerialPort;
        } catch (Throwable tr) {
            Log.e("feisher","打开串口失败"+tr);

            close();
            return null;
        }
    }

    /**
     * 关闭串口
     */
    public void close() {
        if (mReadThread != null) {
            mReadThread.close();
        }
        if (mOutputStream != null) {
            try {
                mOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (mWriteThread != null) {
            mWriteThread.quit();
        }

        if (mSerialPort != null) {
            mSerialPort.close();
            mSerialPort = null;
        }
    }

    /**
     * 发送数据
     *
     * @param datas
     * @return
     */
    private void sendData(byte[] datas) throws Exception {
        mOutputStream.write(datas);
    }

    /**
     * (rx包裹)发送数据
     *
     * @param datas
     * @return
     */
    private Observable<Object> rxSendData(final byte[] datas) {

        return Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
                try {
                    sendData(datas);
                    emitter.onNext(new Object());
                } catch (Exception e) {

                    Log.e("feisher","发送：" + ByteUtil.bytes2HexStr(datas) + " 失败"+ e.getMessage());

                    if (!emitter.isDisposed()) {
                        emitter.onError(e);
                        return;
                    }
                }
                emitter.onComplete();
            }
        });
    }

    /**
     * 发送命令包
     */
    public void sendCommand(final String command) {

        // TODO: 2018/3/22  
        Log.i("feisher","发送命令：" + command);

        byte[] bytes = ByteUtil.hexStr2bytes(command);
        rxSendData(bytes).subscribeOn(mSendScheduler).subscribe(new Observer<Object>() {

            @Override
            public void onSubscribe(Disposable d) {
                
            }

            @Override
            public void onNext(Object o) {
//                LogManager.instance().post(new SendMessage(command));
            }

            @Override
            public void onError(Throwable e) {
                Log.e("feisher","发送失败"+e.getMessage());
            }

            @Override
            public void onComplete() {

            }
        });
    }

    //----------------------------------------------------
    private class ReadThread extends Thread {

        private BufferedInputStream mInputStream;

        ReadThread(InputStream is){
            mInputStream = new BufferedInputStream(is);
        }

        @Override
        public void run() {
            super.run();
            byte[] received = new byte[1024];
            int size;

            Log.e("feisher","开始读线程");

            while (true) {

                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                try {

                    int available = mInputStream.available();

                    if (available > 0) {
                        size = mInputStream.read(received);
                        if (size > 0) {
                            onDataReceive(received, size);
                        }
                    } else {
                        // 暂停一点时间，免得一直循环造成CPU占用率过高
                        SystemClock.sleep(1);
                    }
                } catch (IOException e) {
                    Log.e("feisher","读取数据失败"+e.getMessage());
                }
                //Thread.yield();
            }

            Log.e("feisher","结束读进程");
    }
    }

    /**
     * 处理获取到的数据
     *
     * @param received
     * @param size
     */
    private void onDataReceive(byte[] received, int size) {
        // TODO: 2018/3/22 解决粘包、分包等
        String hexStr = ByteUtil.bytes2HexStr(received, 0, size);

        Log.e("feisher_Receive_hexStr",hexStr);
        Log.e("feisher_Receive_size",size+"");
        onDataReceived(received,size);

    }

    /**
     * 停止读线程
     */
    public void closeReadThread() {
        try {
            mInputStream.close();
        } catch (IOException e) {
            Log.e("feisher","异常"+ e.getMessage());
        } finally {
            thread.interrupt();
        }
    }

    //----------------------------------------------------
    protected abstract void onDataReceived(byte[] received, int size);


//    public interface ReadDataListener {
//        void onReadData(byte[] var1,String hexStr);
//    }
//
//    public void registerListener(ReadDataListener listener) {
//        this.readDataListener=listener;
//    }

}
